home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Users Group Library 1996 July
/
C-C++ Users Group Library July 1996.iso
/
listings
/
v_08_09
/
8n09039a
< prev
next >
Wrap
Text File
|
1990-07-19
|
16KB
|
546 lines
/* > DPRINTF.C
* dprintf -- Source Code
* (C) August 30 1989 Arkin Asaf
* All rights reserved
* References:
* C: A Reference Manual/Chapter 17, pp 328-340
* The Waite Group's Guide to ANSI C/Chapter 7, pp 84-87 */
/* Include files: */
#include <ctype.h>
#include <setjmp.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Macro constants:- TRUE/FALSE, Flags mask bits, and
* argument size types.
* Macros:- Maximum and Minimum expand to yield the maximum
* or minimum of two expressions; ToValue gives the decimal
* value of an ASCII digit and ToDigit returns a digit from
* a value in any radix. N.B.: It goes without saying that
* the macro parameters must contain no operations of con-
* sequence, for they will be carried out more than once. */
#define TRUE 1
#define FALSE 0
#define MaskJustify 0x01 /* - Left justify value within
* field */
#define MaskPlusSign 0x02 /* + Precede positive value
* with plus */
#define MaskSpace 0x04 /* sp Precede positive value
* with space */
#define MaskZeros 0x08 /* 0 Justify value with zeros */
#define MaskVarient 0x10 /* # Output value in varient
* format */
#define TypeNormal 1 /* int/double */
#define TypeShort 2 /* short (meaningless) */
#define TypeLong 3 /* long int */
#define TypeDouble 4 /* long double */
#define Maximum(a,b) ((a)>(b)?(a):(b))
#define Minimum(a,b) ((a)<(b)?(a):(b))
#define ToValue(a) ((a)-'0')
#define ToDigit(a) ((a)<10?(a)+'0':(a)-10+'A')
/* OutFunc (of type dprintf_fp) points to a putchar-like
* function, which performs all output. Called with a
* character int as parameter, the function returns EOF
* only if an output error occured.*/
typedef int (*dprintf_fp)(int);
static dprintf_fp OutFunc;
/* Function declarations: */
int dprintf(dprintf_fp, const char *, ...);
int vdprintf(dprintf_fp, const char *, va_list);
static void PrintDecimal(long, int, int, char, int *);
static void PrintRadix(unsigned long, int, int, char, char,
int *);
static void PrintFloat(long double, int, int, char, char,
int *);
static void Print(char *, char *, int, int, char, int *);
static int ToInteger(char **, unsigned long, int, int);
static void dputc(int);
/* dputc employs this longjmp buffer in the event of an
* output error. */
jmp_buf dputc_Buf;
/* int dprintf(dprintf_fp, const char *, ...)
* dprintf accepts pointers to a putchar-like function and
* a format string. It then passes them to vdprintf, along
* with a pointer to the variable arguments list. */
int dprintf(dprintf_fp Func, const char *Format, ...)
{
int Return;
va_list Args;
va_start(Args,Format);
Return=vdprintf(Func,Format,Args);
va_end(Args);
return Return;
}
/* int vdprintf(dprintf_fp, const char *, va_list)
* vdprintf is an implementation of vprintf, as defined in
* the ANSI standard, with an additional
* pointer-to-function as its first parameter. On exit,
* vdprintf returns the number of characters successfully
* printed, EOF if an error occured. */
int vdprintf(dprintf_fp Func, const char *Format,
va_list Args)
{
char Flags, Size, *Ptr;
int Width, Precis, OutCnt = 0;
long Int;
unsigned long UnsgInt;
long double Float;
char *FlagsList = "-+ 0#", *TypesList = "hlL";
/* The pointer-to-function assigns to static variable
* OutFunc, rather than being passed through three layers
* of functions. The longjmp buffer is then initialized,
* so dputc can return in case of an output error. */
OutFunc=Func;
if (setjmp(dputc_Buf))
return EOF;
/* The format string is scanned a character at a time:
* %'s are processed, all other characters are merely
* echoed to the output. */
for (; *Format; ++Format)
{
if (*Format!='%')
{
dputc(*Format);
++OutCnt;
continue;
}
/* An output format can start with a combination of
* five flags: - + spc 0 #. Flags is set accordingly. */
if (!*++Format)
return EOF;
Flags=0;
while ((Ptr=strchr(FlagsList,*Format))!=NULL)
{
Flags|=1<<(Ptr-FlagsList);
++Format;
}
/* Read width (zero assumed, if absent) and precision
* (-1 assumed, if absent): width must not start with
* a zero; precision precedes with a period -- if no
* precision follows the period, zero is assumed; an
* int argument is consumed for the width or precision,
* if an * replaces the value of either. */
Width=0;
if (*Format=='*')
{
Width=va_arg(Args,int);
++Format;
}
else
while (isdigit(*Format))
Width=Width*10+ToValue(*Format++);
if (*Format=='.')
{
Precis=0;
if (*++Format=='*')
{
Precis=va_arg(Args,int);
++Format;
}
else
while (isdigit(*Format))
Precis=Precis*10+ToValue(*Format++);
}
else
Precis=-1;
/* An argument is either int (default), short int ('h'
* -- meaningless), long int ('l'), double (default
* float), or long double ('L'). */
if ((Ptr=strchr(TypesList,*Format))!=NULL)
{
Size=Ptr-TypesList+TypeShort;
++Format;
}
else
Size=TypeNormal;
/* Consume one output format letter.
* Auxiliary functions process most formats, keeping
* vdprintf short, or else it may fail to compile. */
switch (*Format)
{
case 'd':
case 'i':
if (Size==TypeLong)
Int=va_arg(Args,long);
else
Int=va_arg(Args,int);
PrintDecimal(Int,Width,Precis,Flags,&OutCnt);
break;
case 'u':
case 'o':
case 'x': case 'X':
if (Size==TypeLong)
UnsgInt=va_arg(Args,unsigned long);
else
UnsgInt=va_arg(Args,unsigned);
PrintRadix(UnsgInt,Width,Precis,Flags,*Format,
&OutCnt);
break;
case 'c':
{
static char Char[2]= {0,0};
Char[0]=va_arg(Args,unsigned char);
Print(Char,NULL,Width,-1,Flags,&OutCnt);
break;
}
case 's':
Ptr=va_arg(Args,char *);
Print(Ptr,NULL,Width,Precis,Flags,&OutCnt);
break;
case 'f':
case 'e': case 'E':
case 'g': case 'G':
if (Size==TypeDouble)
Float=va_arg(Args,long double);
else
Float=va_arg(Args,double);
PrintFloat(Float,Width,Precis,Flags,*Format,&OutCnt);
break;
case 'p':
/* The pointer-to-void argument is cast to long
* unsigned, assuming pointer representation to
* remain intact. */
UnsgInt=(unsigned long) va_arg(Args,void *);
PrintRadix(UnsgInt,Width,Precis,Flags,*Format,
&OutCnt);
break;
case 'n':
*(va_arg(Args,int *))=OutCnt;
break;
case '%':
Print("%",NULL,Width,-1,Flags,&OutCnt);
break;
default:
return EOF;
}
}
return OutCnt;
}
/* void PrintDecimal(long, int, int, char, int *)
* Print a decimal value (%d or %i) with a sign prefix. */
static void PrintDecimal(long Int, int Width, int Precis,
char Flags, int *OutCnt)
{
char *Prefix;
char *Buffer;
if(Int<0)
{
Int=-Int;
Prefix="-";
}
else
{
if (Flags&MaskPlusSign)
Prefix="+";
else
if (Flags&MaskSpace)
Prefix=" ";
else
Prefix=NULL;
}
ToInteger(&Buffer,Int,10,Precis);
Print(Buffer,Prefix,Width,-1,Flags,OutCnt);
free(Buffer);
}
/* void PrintRadix(unsigned long,